﻿//
//Description : Classe de base pour les champs d'un entité
//Auteur : Marc-Eric Boisvert
//Date Création : 31 mars 2008
//Révisions:
//
using System;
using Framework.Data.DataType;

namespace Framework.Data.Core
{

    [Serializable()]
    public abstract class BaseField : IField, IReadOnly, IListField
    {

        #region "Membres"

        //Nom du champ
        protected string _name = string.Empty;
        //Valeur courante
        protected object _value = null;
        //Valeur originale
        protected object _originalValue = null;
        //Indicateur lecture-seule
        protected bool _readOnly = false;
        //Type de la valeur
        protected System.Type _fieldValueType;
        //Indicateur d'affichage du champ dans les listes
        protected bool _displayFieldInList = true;
        //Indicateur d'affichage du champ dans les listes
        protected bool _displayFieldInEditableList = true;
        //Nom de la colonne dans les listes
        protected string _listColumnName = string.Empty;
        //Format d'affichage dans les listes
        protected string _formatString = string.Empty;
        //Format d'affichage dans les listes
        protected IFormatProvider _formatProvider = null;
        //L'entité auquel le champ appartient

        protected IBaseEntity _entity = null;
        #endregion

        #region "Constructeurs"

        //
        //Constructeurs
        //
        public BaseField(IBaseEntity entity, string name, Type fieldValueType)
            : this(entity, name, fieldValueType, false)
        {
        }

        //
        //Constructeurs
        //
        public BaseField(IBaseEntity entity, string name, Type fieldValueType, bool readOnly)
            : this(entity, name, fieldValueType, readOnly, true)
        {
        }

        //
        //Constructeurs
        //
        public BaseField(IBaseEntity entity, string name, Type fieldValueType, bool readOnly, bool displayFieldInList)
            : this(entity, name, fieldValueType, readOnly, displayFieldInList, true)
        {
        }

        //
        //Constructeurs
        //
        public BaseField(IBaseEntity entity, string name, Type fieldValueType, bool readOnly, bool displayFieldInList, bool displayFieldInEditableList)
            : this(entity, name, fieldValueType, readOnly, displayFieldInList, displayFieldInEditableList, name)
        {
        }

        public BaseField(IBaseEntity entity, string name, Type fieldValueType, bool readOnly, bool displayFieldInList, bool displayFieldInEditableList, string listColumnName)
        {
            this._name = name;
            this._fieldValueType = fieldValueType;
            this._readOnly = readOnly;
            this._displayFieldInList = displayFieldInList;
            this._displayFieldInEditableList = displayFieldInEditableList;
            this._listColumnName = listColumnName;
            this._entity = entity;
        }

        #endregion

        #region "Méthodes"

        //
        //Fonction qui permet d'afficher la valeur courante du champ
        //
        public override string ToString()
        {
            if ((this.Value != null))
            {
                if (this._formatString != string.Empty)
                {
                    if (this._fieldValueType.Equals(typeof(DateTime)) && ((DateTime)this.Value).Ticks == 0)
                    {
                        return "";
                    }
                    else
                    {
                        return this._fieldValueType.InvokeMember("ToString", System.Reflection.BindingFlags.InvokeMethod, null, this.Value, new object[] { this._formatString }).ToString();
                    }
                }
                else
                {
                    return this.Value.ToString();
                }
            }
            else
            {
                return string.Empty;
            }
        }

        #endregion

        #region "IField"

        /// <summary>
        /// L'entité auquel le champ appartient
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        public IBaseEntity Entity
        {
            get { return this._entity; }
        }

        /// <summary>
        /// Procédure qui permet d'accepter la nouvelle valeur du champ
        /// </summary>
        /// <remarks></remarks>
        public virtual void AcceptChanges()
        {
            this._originalValue = this._value;
        }

        public virtual System.Type FieldValueType
        {
            get { return this._fieldValueType; }
        }

        public virtual string FormatString
        {
            get { return this._formatString; }
            set { this._formatString = value; }
        }

        public virtual IFormatProvider FormatProvider
        {
            get { return this._formatProvider; }
            set { this._formatProvider = value; }
        }

        public virtual bool IsDirty
        {
            get
            {
                if ((this.OriginalValue != null) && (!object.ReferenceEquals(this.OriginalValue, System.DBNull.Value)))
                {
                    return !this._originalValue.Equals(this._value);
                }
                else
                {
                    return (this.Value != null);
                }
            }
        }

        public virtual bool IsNull
        {
            get { return ((Value == null) || (Value.Equals(DBNull.Value))); }
        }

        public virtual string Name
        {
            get { return this._name; }
            set { this._name = value; }
        }

        public virtual object OriginalValue
        {
            get { return this._originalValue; }
            set
            {
                if (!this.ReadOnly)
                {
                    this._originalValue = value;
                }
                else
                {
                    throw new ArgumentException("Cannot update field " + this.Name + " because it's read only.");
                }
            }
        }

        /// <summary>
        /// Procédure qui permet  de rejeter la modification au champ
        /// </summary>
        /// <remarks></remarks>
        public virtual void RejectChanges()
        {
            this._value = this._originalValue;
        }

        public virtual object Value
        {
            get
            {
                if ((this._value == null) || (this._value.Equals(DBNull.Value)))
                {
                    return null;
                }
                return this._value;
            }
            set
            {
                if (!this.ReadOnly)
                {
                    this._value = value;
                }
                else
                {
                    throw new ArgumentException("Cannot update field " + this.Name + " because it's read only.");
                }
            }
        }

        /// <summary>
        /// Procédure d'initialization de la valeur
        /// </summary>
        /// <param name="value"></param>
        /// <remarks></remarks>
        public virtual void InitializeValue(object value)
        {
            if ((this._fieldValueType.Equals(typeof(bool))) & ((value != null) || (value.Equals(DBNull.Value))))
            {
                this._value = Convert.ToBoolean(value);
                this._originalValue = Convert.ToBoolean(value);
            }
            else if ((this._fieldValueType.Equals(typeof(string))) & ((value != null) && (value.Equals(DBNull.Value))))
            {
                this._value = "";
                this._originalValue = "";
            }
            else if ((this._fieldValueType.Equals(typeof(Clob))) & ((value != null) && (value.Equals(DBNull.Value))))
            {
                this._value = "";
                this._originalValue = "";
            }
            else if ((this._fieldValueType.Equals(typeof(DateTime))) & ((value != null) && (value.Equals(DBNull.Value))))
            {
                this._value = new DateTime(0);
                this._originalValue = new DateTime(0);
            }
            else if ((this._fieldValueType.Equals(typeof(decimal))) & ((value != null) && (value.Equals(DBNull.Value))))
            {
                this._value = null;
                this._originalValue = null;
            }
            else
            {
                this._value = value;
                this._originalValue = value;
            }
        }

        #endregion

        #region "IListField"

        public virtual bool DisplayFieldInList
        {
            get { return this._displayFieldInList; }
            set { this._displayFieldInList = value; }
        }

        public virtual bool DisplayFieldInEditableList
        {
            get { return this._displayFieldInEditableList; }
            set { this._displayFieldInEditableList = value; }
        }

        public virtual string DisplayText
        {
            get
            {
                if (this._value != null)
                {
                    if (this._formatString != null && this._formatProvider != null)
                    {
                        return string.Format(this.FormatProvider, "{0}", this._value);
                    }
                    else
                    {
                        return this.ToString();
                    }
                }
                else
                {
                    return string.Empty;
                }
            }
        }

        public virtual string ListColumnName
        {
            get { return this._listColumnName; }
            set { this._listColumnName = value; }
        }

        #endregion

        #region "IReadOnly"
        public virtual bool ReadOnly
        {
            get { return this._readOnly; }
            set { this._readOnly = value; }
        }
        #endregion

    }
}